/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package race.component;

import java.io.IOException;
import java.util.Random;
import java.util.Vector;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.game.TiledLayer;
import race.model.Point;
import race.model.Racer;
import race.model.SpeedBooster;
import race.util.BackgroundUtil;
import race.util.Tool;

/**
 *
 * @author BBXP
 */
public class RaceCanvas extends GameCanvas implements Runnable {

    private String[] ABV = {"st", "nd", "rd", "th"};

    private int spaceBetweenRacer ;
    
    public static final int EASY = 1;
    public static final int NORMAL = 2;
    public static final int HARD = 3;

    private boolean stopped = true;
    private boolean paused = true;
    public static int tiledSize;
    private LayerManager layerManager;
    private Racer racer;
    private TiledLayer roadLayer;
    private TiledLayer collisionLayer;
    private TiledLayer foreCollisionLayer;
    private int rightViewLimit;
    private Racer[] racers;
    private boolean countDownFinished = false;
    private long timeLapse = 0;
    private int racerStartPositionY =  BackgroundUtil.TOTAL_HEIGHT - 100;
    private int finishLine = 60;
    private int totalDistance;
    private int distanceBarLength;
    private long lastTime;
    private int level = EASY;

    private int canvasWidth;
    private int canvasHeight;
    
    private int finishTime;
    private String recordStr;
    private String rankStr;

    private Random r = new Random();
    private SpeedBooster[] boosters = new SpeedBooster[4];

    public RaceCanvas() {
        super(false);
        canvasWidth = getWidth();
        canvasHeight = getHeight();
        distanceBarLength = canvasWidth - BackgroundUtil.TILE_WIDTH * 2;
        System.out.println("width: " + this.getWidth());
        layerManager = new LayerManager();
        totalDistance = BackgroundUtil.TOTAL_HEIGHT - 100 - finishLine;
        racers = new Racer[HARD];
        spaceBetweenRacer = Racer.WIDTH*2;
        
        rightViewLimit = BackgroundUtil.TOTAL_WIDTH - getWidth() / 2;
        try {
            roadLayer = new BackgroundLayer(Image.createImage("/images/bgmap_small.png"), BackgroundUtil.COLS, BackgroundUtil.ROWS, BackgroundUtil.getRoadMap());
            collisionLayer = new BackgroundLayer(Image.createImage("/images/bgmap_small.png"), BackgroundUtil.COLS, BackgroundUtil.ROWS, BackgroundUtil.getEasyCollisionMap());
            
            foreCollisionLayer = new BackgroundLayer(Image.createImage("/images/bgmap_small.png"), BackgroundUtil.COLS, BackgroundUtil.ROWS, BackgroundUtil.getEasyForeCollisionMap());
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        racer = new Racer(BackgroundUtil.TILE_WIDTH * 2, racerStartPositionY, 1, 2, finishLine, 0);
        for(int i = 0; i < HARD; i++){
            racers[i] = new Racer(racer.getX() + spaceBetweenRacer  * (i+1), racerStartPositionY, 1, 2, finishLine, i+1);
            racers[i].initAutoControl(foreCollisionLayer);
            racers[i].setTargetSprite(racer.getSprite());
        }
        layerManager.append(racer.getSprite());
        layerManager.append(collisionLayer);
        layerManager.append(roadLayer);
        for(int i = 0; i < boosters.length; i++){
            boosters[i] = new SpeedBooster();
        }
        reset();
            //draw(getGraphics());
        
        //draw(getGraphics());
    }

    protected void keyPressed(int keyCode) {
         
        int gameAction = this.getGameAction(keyCode);
        if (gameAction == this.UP) {
            racer.accelerate();
        } else if (gameAction == this.DOWN) {
            racer.decelerate();
        } else if (gameAction == this.LEFT) {
            racer.turnLeft();
        } else if (gameAction == this.RIGHT) {
            racer.turnRight();
        } 
    }



    protected void keyReleased(int keyCode) {
        int gameAction = this.getGameAction(keyCode);
        if (gameAction == this.LEFT ) {
            racer.goStraight();
        } else if (gameAction == this.DOWN ) {
            racer.keepSteady();
        } else if (gameAction == this.UP ) {
            racer.keepSteady();
        } else if (gameAction == this.RIGHT ) {
            racer.goStraight();
        }
    }

    private void draw(Graphics g) {
        layerManager.paint(g, 0, 0);
        int second = (int)(timeLapse / 1000)-5;
        if(second > 0 ){
            g.drawString(second+" second", 170, 0, 0);
        }
        if(!countDownFinished){
           g.setColor(255, 0, 0);
            g.drawString("===="+(4 - timeLapse / 1000)+"====", 100, 150, 0);
            g.setColor(255, 255, 0);
            g.fillTriangle(racer.getX()+5, canvasHeight - 135, racer.getX() + 15, canvasHeight - 135, racer.getX() + 10, canvasHeight - 130);
        }
        g.setColor(255, 255, 255);
        g.fillRect(BackgroundUtil.TILE_WIDTH, canvasHeight-40, distanceBarLength+5, 10);
        g.setColor(200, 0, 0);
        for(int i = 0; i < level; i++){
             int pos = (int)((totalDistance - racers[i].getY() + 100f + finishLine) / (float)totalDistance * distanceBarLength);
            if(pos > distanceBarLength){
                pos = distanceBarLength;
            }
            g.fillArc(BackgroundUtil.TILE_WIDTH+pos, canvasHeight-37, 5, 5, 0, 360);
        }
        g.setColor(0, 200, 0);
        int pos = (int)((totalDistance - racer.getY() + 100f + finishLine) / (float)totalDistance * distanceBarLength);
        if(pos > distanceBarLength){
            pos = distanceBarLength;
        }
        g.fillArc(BackgroundUtil.TILE_WIDTH+pos, canvasHeight-37, 5, 5, 0, 360);
        g.setColor(255, 255, 0);
        g.drawString(racer.getSpeed()+"", 48, canvasHeight-60, 0);
        
        if(paused){
            g.setColor(0, 0, 0);
            g.drawString("Paused", canvasWidth/2-20, canvasHeight/2-10, 0);
        }

        if(racer.isFinished()){
            g.setColor(0, 0, 0);
            g.fillRect(BackgroundUtil.TILE_WIDTH, BackgroundUtil.TILE_HEIGHT, canvasWidth - BackgroundUtil.TILE_WIDTH*2, 60);
            g.setColor(255, 255, 255);
            if(rankStr == null || recordStr == null){ constructFinalMsg();}
            g.drawString(rankStr, canvasWidth/2-15, 35, 0);
            g.drawString(recordStr,80,60, 0);
        }else{         
        }
    }


    public void run() {
        lastTime = System.currentTimeMillis();
        stopped = false;
        paused = false;
        while (!stopped) {
           
            if (!paused) {
                if (racer.getCollisionSprite().collidesWith(collisionLayer, false)) {
                    racer.limitTheSpeed();
                }
                for(int i = 0; i < level; i++){
                    if(racer.getCollisionSprite().collidesWith(racers[i].getCollisionSprite(), false)){
                        if(racer.getY() < racers[i].getY()){
                            racer.limitTheSpeed();
                        }else{
                            racers[i].limitTheSpeed();
                        }
                        if(racer.getX() < racers[i].getX()){
                            racer.bounceOffToLeft();
                            racers[i].bounceOffToRight();
                        }else{
                            racer.bounceOffToRight();
                            racers[i].bounceOffToLeft();
                        }
                    }
                    racers[i].autoControl(collisionLayer);
                    if(racers[i].getCollisionSprite().collidesWith(collisionLayer, false)){
                        racers[i].limitTheSpeed();
                    }
                }
                for(int i = 0; i < boosters.length; i++){
                    if(racer.getSprite().collidesWith(boosters[i].getSprite(), false)){
                        racer.maxSpeed();
                    }
                    for(int j = 0; j < level; j++){
                        if(racers[j].getSprite().collidesWith(boosters[i].getSprite(), false));
                    }
                }
                if(countDownFinished){
                    racer.update();
                    for(int i = 0; i < level; i++){
                        racers[i].update();
                    }
                }
                if(!racer.isFinished()){
                    timeLapse += (System.currentTimeMillis() - lastTime);
                    lastTime = System.currentTimeMillis();
                }else{
                    finishTime = (int)(timeLapse/1000)-5;
                }
                int viewY = racer.getY() - 200;
                int viewX = racer.getX() - (getWidth() / 2);
                if (viewY < 0) {
                    viewY = 0;
                }
                if (viewX < 0) {
                    viewX = 0;
                } else if (racer.getX() > rightViewLimit) {
                    viewX = BackgroundUtil.TOTAL_WIDTH - getWidth();
                }
                layerManager.setViewWindow(viewX, viewY, getWidth(), getHeight());
                if(timeLapse > 5000){
                    countDownFinished = true;
                }
                
                
            }else{
                lastTime = System.currentTimeMillis();
            }
            try {
                Thread.sleep(40);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            draw(this.getGraphics());
            this.flushGraphics();
            
        }
    }

    public boolean isStopped() {
        return stopped;
    }

    public boolean isPaused() {
        return paused;
    }

    public void stop() {
        stopped = true;
    }

    public void pause() {
        paused = true;

    }

    protected void hideNotify(){
        pause();
    }

//    protected void showNotify(){
//        resume();
//    }
    public void resume() {
        paused = false;
    }

    private void constructFinalMsg(){
        int finishCount = 0;
        if(racer.isFinished()){
            finishCount++;
        }
        for(int i = 0; i < level; i++){
            if(racers[i].isFinished()){
                finishCount++;
            }
        }
        if(finishCount-1 < 0){
            recordStr = "ERROR!";
            return;
        }
        rankStr = finishCount+" "+ABV[finishCount-1];
        int r = Tool.updateRecord(level, finishTime);
        if(r == -1){
            recordStr = "New Record: "+finishTime;
        }else{
            recordStr = "Hightest :"+ r;
        }
    }

    public void reset(){
        recordStr = null;
        rankStr = null;
        layerManager.remove(roadLayer);
        //stopped = false;
        paused = false;
        racer.reset();
        racer.update();
        layerManager.remove(collisionLayer);
        try {
            collisionLayer = new BackgroundLayer(Image.createImage("/images/bgmap_small.png"), BackgroundUtil.COLS, BackgroundUtil.ROWS, BackgroundUtil.getCollisionMap(level));
            foreCollisionLayer = new BackgroundLayer(Image.createImage("/images/bgmap_small.png"), BackgroundUtil.COLS, BackgroundUtil.ROWS, BackgroundUtil.getForeCollisionMap(level));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        layerManager.append(collisionLayer);
        layerManager.append(roadLayer);
        for(int i = 0; i < level; i++){
            racers[i].initAutoControl(foreCollisionLayer);
            racers[i].reset();
            racers[i].update();
            if(level > EASY){
                if(r.nextInt(level) > EASY){
                    racers[i].setOffensive(true);
                }else{
                    racers[i].setOffensive(false);
                }
            }
        }
        Vector points = new Vector();
        for(int i = 0; i < boosters.length; i++){
            Point p = boosters[i].randomPosition();
            layerManager.remove(boosters[i].getSprite());
            while(points.contains(p)){
                p = boosters[i].randomPosition();
            }
            points.addElement(p);
            layerManager.insert(boosters[i].getSprite(), 1);
        }
        for(int i = 0; i < HARD; i++){
            layerManager.remove(racers[i].getSprite());
            if(i < level){
                layerManager.insert(racers[i].getSprite(), 1);
            }
        }
        countDownFinished = false;
        timeLapse = 0;
        lastTime = System.currentTimeMillis();
    }

    public int getLevel(){
        return level;
    }
    public void setLevel(int level){
        this.level = level;
    }
}
